home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / WSKSOCK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  25.6 KB  |  833 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.17  $
  6. //
  7. // Winsock for OWL subsystem.
  8. // Based on work by Paul Pedriana, 70541.3223@compuserve.com
  9. //----------------------------------------------------------------------------
  10. #include <owl/pch.h>
  11. #if !defined(OWL_WINSOCK_H)
  12. # include <owl/winsock.h>
  13. #endif
  14.  
  15. OWL_DIAGINFO;
  16.  
  17. //
  18. // default constructor for a socket.  You can set the individual members of
  19. // the TSocket later.
  20. //
  21. TSocket::TSocket()
  22. :
  23.   Window(this),
  24.   Family(PF_UNSPEC),
  25.   Type(0),
  26.   Protocol(0),
  27.   MaxReadBufferSize(N_DEF_MAX_READ_BUFFFER_SIZE),
  28.   Bound(false),
  29.   SaveSocket(0),
  30.   Handle(INVALID_SOCKET)
  31. {
  32.   Init();
  33. }
  34.  
  35. //
  36. // TSocket(SOCKET&) is a constructor based on a Winsock SOCKET descriptor.
  37. //
  38. TSocket::TSocket(SOCKET& newS)
  39. :
  40.   Window(this),
  41.   MaxReadBufferSize(N_DEF_MAX_READ_BUFFFER_SIZE),
  42.   Bound(false),
  43.   SaveSocket(0),
  44.   Handle(newS)
  45. {
  46.   int temp;
  47.   GetMyAddress(SocketAddress, temp, Handle); // Fills in our address information.
  48.   Family = SocketAddress.sa_family;
  49.   GetPeerAddress(SocketAddress, temp, Handle); // Fills in out Peer's address info if it exists.
  50.   Init();
  51. }
  52.  
  53. //
  54. // This is the standard constructor for a TSocket.  It doesn't call socket() nor bind().  You must
  55. //  do those independently.
  56. //
  57. TSocket::TSocket(TSocketAddress& newSocketAddress, int newFamily, int newType, int newProtocol)
  58. :
  59.   Window(this),
  60.   SocketAddress(newSocketAddress),
  61.   Family(newFamily),
  62.   Type(newType),
  63.   Protocol(newProtocol),
  64.   MaxReadBufferSize(N_DEF_MAX_READ_BUFFFER_SIZE),
  65.   Bound(false),
  66.   SaveSocket(0),
  67.   Handle(INVALID_SOCKET)
  68. {
  69.   Init();
  70. }
  71.  
  72. //
  73. // This TSocket destructor will close the socket it if has not be closed already.
  74. // It will also delete the friend notification window as well.
  75. //
  76. TSocket::~TSocket()
  77. {
  78.   if (Handle != INVALID_SOCKET && !SaveSocket) {
  79.     SetLingerOption(0, 60); //Don't wait till data gets sent.  Just kill the socket now.
  80.     CloseSocket();
  81.   }
  82. }
  83.  
  84. //
  85. // This function is an intitialization function called by the TSocket constructors.  It
  86. //  simply creates the friend window that the TSocket needs for Winsock notifications.
  87. //
  88. void TSocket::Init()
  89. {
  90.   // This is for initialization steps that are common to all constructors.
  91.   //
  92.   LastError = 0;
  93.   try {
  94.      Window.Create();
  95.   }
  96.   catch (...) {
  97.     //::MessageBox();
  98.   }
  99. }
  100.  
  101. //
  102. // Check the return error value from a sockets call, caching the last error
  103. // if one occured, i.e error is non-zero. Return a Winsock error/noerror code.
  104. //
  105. int TSocket::SocketsCallCheck(int error)
  106. {
  107.   if (error) {
  108.     LastError = TWinSockDll::WSAGetLastError();
  109.     return WINSOCK_ERROR;
  110.   }
  111.   return WINSOCK_NOERROR;
  112. }
  113.  
  114. //
  115. // Does a deep copy of the TSocket, as much as possible.
  116. //
  117. TSocket& TSocket::operator =(TSocket& newSocket)
  118. {
  119.   Family            = newSocket.Family;
  120.   Type              = newSocket.Type;
  121.   Protocol          = newSocket.Protocol;
  122.   LastError         = newSocket.LastError;
  123.   Handle            = newSocket.Handle;
  124.   SocketAddress     = newSocket.SocketAddress;
  125.   PeerSocketAddress = newSocket.PeerSocketAddress;
  126.   SaveSocket        = newSocket.SaveSocket;
  127.  
  128.   // Copy the friend (helper) window.  Note that there is an operator= defined
  129.   //  for the class TSocketWindow.  However, the TSocketWindow::operator= will
  130.   //  set its 'SocketParent' member to be the newSocket SocketWindow's previous
  131.   //  TSocket parent, which may not be us.  Thus, after setting 'Window =
  132.   //  newSocket.Window;', we set 'Window.SocketParent = this;'.
  133.   //
  134.   Window              = newSocket.Window;
  135.   Window.SocketParent = this;
  136.  
  137.   return *this;
  138. }
  139.  
  140. #if defined(BI_NAMESPACE)
  141. namespace OWL {
  142. #endif
  143.  
  144. //
  145. // While it is possible that two sockets could refer to the same SOCKET (though
  146. //  this would likely create a mess if not governed with care), it is defined as
  147. //  not possible that two Sockets could lhave the same window member.  THis is
  148. //  because the window is created uniquely on construction for each TSocket.
  149. //
  150. bool operator ==(const TSocket& socket1, const TSocket& socket2)
  151. {
  152.   return socket1.Handle == socket2.Handle && socket1.Window == socket2.Window;
  153. }
  154.  
  155. #if defined(BI_NAMESPACE)
  156. } // namespace OWL
  157. #endif
  158.  
  159. //
  160. // See SocketWindow::StartAcceptNotification() for documentation
  161. //
  162. int TSocket::StartAcceptNotification()
  163. {
  164.   int error = Window.StartAcceptNotification();
  165.   if (error == WINSOCK_ERROR) {
  166.     LastError = Window.GetLastError();
  167.   }
  168.   return error;
  169. }
  170.  
  171. //
  172. // See TSocketWindow::StartRegularNotification() for documentation
  173. //
  174. int TSocket::StartRegularNotification()
  175. {
  176.   int error = Window.StartRegularNotification();
  177.   if (error == WINSOCK_ERROR) {
  178.     LastError = Window.GetLastError();
  179.   }
  180.   return error;
  181. }
  182.  
  183. //
  184. //
  185. //
  186. int TSocket::StartCustomNotification(int selectionOptions)
  187. {
  188.   int error = Window.StartCustomNotification(selectionOptions);
  189.   if (error == WINSOCK_ERROR) {
  190.     LastError = Window.GetLastError();
  191.   }
  192.   return error;
  193. }
  194.  
  195. //
  196. // See SocketWindow::CancelNotification() for documentation
  197. //
  198. int TSocket::CancelNotification()
  199. {
  200.   int error = Window.CancelNotification();
  201.   if (error == WINSOCK_ERROR) {
  202.     LastError = Window.GetLastError();
  203.   }
  204.   return error;
  205. }
  206.  
  207. //
  208. // The SetSocketStyle function can be used to set or change some TSocket member data.
  209. // Note that the newFamily is also represented in the TSocketAddress member, thus they
  210. //  should match.
  211. //
  212. void TSocket::SetSocketStyle(int newFamily, int newType, int newProtocol)
  213. {
  214.   Family   = newFamily;
  215.   Type     = newType;
  216.   Protocol = newProtocol;
  217. }
  218.  
  219. //
  220. // Converts a string protocol to integer value.
  221. // Makes assumptions about the protocol string.
  222. // Only "tcp" and udp return valid values.
  223. //
  224. int TSocket::ConvertProtocol(char* protocol)
  225. {
  226.   if (!protocol)
  227.     return IPPROTO_TCP;
  228.   if (strcmp("tcp", protocol) == 0)
  229.     return IPPROTO_TCP;
  230.   if(strcmp("udp", protocol) == 0)
  231.     return IPPROTO_UDP;
  232.   return IPPROTO_IP;
  233. }
  234.  
  235. //
  236. // The CreateSocket function is much like the Winsock socket() function.
  237. // This function assumes that nFamily, nType, and nProtocol are already set properly.
  238. // Note also that since the return of socket() is assigned to 's', that 's' must not
  239. //  be alredy used.  This is another way of saying that there can only be one
  240. //  SOCKET for each TSocket object.
  241. //
  242. int TSocket::CreateSocket()
  243. {
  244.   Handle = TWinSockDll::socket(Family, Type, Protocol);
  245.   return SocketsCallCheck(Handle == INVALID_SOCKET);
  246. }
  247.  
  248. //
  249. // The CloseSocket() function is much like the Winsock closesocket() function.
  250. //
  251. int TSocket::CloseSocket()
  252. {
  253.   if (Handle != INVALID_SOCKET) {
  254.     int error = TWinSockDll::closesocket(Handle);
  255.     if (error) {
  256.       LastError = TWinSockDll::WSAGetLastError();
  257.       return WINSOCK_ERROR;
  258.     }
  259.   }
  260.   Handle = INVALID_SOCKET;  // It's invalid now.
  261.   Bound = false;
  262.   return WINSOCK_NOERROR;
  263. }
  264.  
  265. //
  266. // The ShutDownSocket() function is much like the Winsock shutdown() function.
  267. // It is important to note that shutting down a socket essentially means that
  268. //  you can't un-shut it down.  It is like a graceful way of preparing to
  269. //  end a session.  It is somewhat like a yellow stoplight.
  270. //
  271. //  You would want to use this function to close your socket, while still allowing data
  272. //  be received from the network.  This is as opposed to CloseSocket(), which kills
  273. //  all transfers in both directions.
  274. //
  275. //  shutMode is one of the enumerations: ShutModeNoRecv, ShutModeNoSend, or ShutModeNoRecvSend.
  276. int TSocket::ShutDownSocket(TShutMode shutMode)
  277. {
  278.   if (Handle != INVALID_SOCKET) {
  279.     int error = TWinSockDll::shutdown(Handle, shutMode);
  280.     if (error) {
  281.       LastError = TWinSockDll::WSAGetLastError();
  282.       return WINSOCK_ERROR;
  283.     }
  284.     Handle = INVALID_SOCKET;  // It's invalid now.
  285.     Bound = false;
  286.   }
  287.   return WINSOCK_NOERROR;
  288. }
  289.  
  290. //
  291. // BindSocket is much like the Winsock bind() function.
  292. // Regardless of what mySocketAddress may have been previously, a call to 'bind()'
  293. //  immediately makes the socket's address the one put into the bind() call.
  294. //  Thus we simply always assign mySocketAddress to be boundSocketAddress.
  295. // The address argument must be in network byte ordering. On the other hand, the
  296. //  SocketAddress class always keeps is addresses in network byte ordering.
  297. //
  298. int TSocket::BindSocket(const TSocketAddress& addressToBindTo)
  299. {
  300.   SocketAddress = addressToBindTo;
  301.  
  302.   // bind() ideally returns 0.
  303.   //
  304.   if (TWinSockDll::bind(Handle, &SocketAddress, sizeof(sockaddr))) {
  305.     LastError = TWinSockDll::WSAGetLastError();
  306.     return WINSOCK_ERROR;
  307.   }
  308.   Bound = true;
  309.   return WINSOCK_NOERROR;
  310. }
  311.  
  312. //
  313. // This BindSocket simply binds with our previously defined member data socket
  314. // address.
  315. //
  316. int TSocket::BindSocket()
  317. {
  318.   return BindSocket(SocketAddress);
  319. }
  320.  
  321. //
  322. // This function stores the address into the reference argument 'socketAddress'.
  323. // 'addressLength' will hold the length of the address.
  324. // 'socket' refers to the socket who's address wil be examined.
  325. //
  326. int TSocket::GetMyAddress(TSocketAddress& socketAddress, int& addressLength, SOCKET& socket)
  327. {
  328.   return SocketsCallCheck(!TWinSockDll::getsockname(socket, &socketAddress, &addressLength));
  329. }
  330.  
  331. //
  332. // This function stores the address into the reference argument 'socketAddress'.
  333. // 'addressLength' will hold the length of the address.
  334. // Uses the SOCKET in my member data as the socket to get the address of.
  335. //
  336. int TSocket::GetMyAddress(TSocketAddress& socketAddress, int& addressLength)
  337. {
  338.   return GetMyAddress(socketAddress, addressLength, Handle);
  339. }
  340.  
  341. //
  342. //The GetPeerAddress() function is much like the Winsock getpeername() function.
  343. //  The Winsock getpeername() function is misnamed; it should be getpeeraddress().
  344. //socketAddress will be changed to have the right addressing info, and nAddressLength
  345. //  will be set to be the address length.
  346. //Note that this function can be used to get the address for any socket descriptor,
  347. //  not just our own socket descriptor.
  348. //
  349. int TSocket::GetPeerAddress(TSocketAddress& socketAddress, int& addressLength, SOCKET& socket)
  350. {
  351.   // This code only works because SOCKET is defined as a uint and not a struct
  352.   //
  353.   if (!socket)
  354.     socket = Handle;
  355.  
  356.   return SocketsCallCheck(!TWinSockDll::getpeername(socket, &socketAddress, &addressLength));
  357. }
  358.  
  359. //
  360. // This version of GetPeerAddress() works on our own socket descriptor.
  361. //
  362. int TSocket::GetPeerAddress(TSocketAddress& socketAddress, int& addressLength)
  363. {
  364.   return GetPeerAddress(socketAddress, addressLength, Handle);
  365. }
  366.  
  367. //
  368. // This may be useful for changing the address or setting the address before
  369. //  binding.  It's no good to change this after binding, as a binding is a
  370. //  permanent association between a socket descriptor and a full address (for
  371. //  IP, this is a ushort port and ulong address).
  372. //
  373. void TSocket::SetMyAddress(TSocketAddress& newSocketAddress)
  374. {
  375.   SocketAddress = newSocketAddress;
  376. }
  377.  
  378. //
  379. // The 'myPeerSocketAddress' member variable is useful for Datagram sockets because it
  380. //  allows them to specify a default destination to send datagrams to.  With a default
  381. //  destination, a datagram socket that always or often sends to one address can simply call
  382. //  the Write() or Send() functions with no address arguments and the data will send
  383. //  to the default address.
  384. // This function can also be used by a stream socket to set the address for a peer
  385. //  that it wants to connect to.
  386. //
  387. void TSocket::SetPeerSocketAddress(TSocketAddress& newPeerSocketAddress)
  388. {
  389.   PeerSocketAddress = newPeerSocketAddress;
  390. }
  391.  
  392. //
  393. // GetDriverWaitingSize() is much like calling ioctlsocket(s, FIONREAD,...) in Winsock.
  394. // It returns the number of bytes waiting to be read on our socket.
  395. // For datagrams, it is the size of the next datagram.
  396. // For streams, it "should" be the total waiting bytes.
  397. //
  398. #pragma warn -cln
  399. ulong TSocket::GetDriverWaitingSize()
  400. {
  401.   ulong charsWaiting;
  402.   if (TWinSockDll::ioctlsocket(Handle, FIONREAD, &charsWaiting)) {
  403.     return 0;
  404.   }
  405.   return charsWaiting;
  406. }
  407. #pragma warn .cln
  408.  
  409. //
  410. // Returns the total number of bytes waiting to be read.
  411. //
  412. ulong TSocket::GetTotalWaitingSize()
  413. {
  414.   return GetDriverWaitingSize();
  415. }
  416.  
  417. //
  418. // This function gets called whenever the socket gets a read notification.  This means
  419. //  that data on the port is ready to be read.
  420. // Thus this function must be subclassed by a DatagramSocket and StreamSocket.
  421. //
  422. TSocket::DoReadNotification(const SOCKET& /*socket*/, int /*nError*/)
  423. {
  424.   return 0;
  425. }
  426.  
  427. //
  428. // The generic socket doesn't know how many bytes it can send, since this limit
  429. //  is dependent on whether the socket is a stream or datagram socket.
  430. // Thus this function must be subclassed by a DatagramSocket and StreamSocket.
  431. //
  432. TSocket::DoWriteNotification(const SOCKET& /*s*/, int /*nError*/)
  433. {
  434.   return 0;
  435. }
  436.  
  437. //
  438. // We don't respond to this in the generic TSocket class.
  439. //
  440. TSocket::DoOOBNotification(const SOCKET& /*s*/, int /*nError*/)
  441. {
  442.   return 0;
  443. }
  444.  
  445. //
  446. // We don't respond to this in the generic TSocket class.
  447. //
  448. TSocket::DoAcceptNotification(const SOCKET& /*s*/, int /*nError*/)
  449. {
  450.   return 0;
  451. }
  452.  
  453. //
  454. // We don't respond to this in the generic TSocket class.
  455. //
  456. TSocket::DoConnectNotification(const SOCKET& /*s*/, int /*nError*/)
  457. {
  458.   return 0;
  459. }
  460.  
  461. //
  462. // We don't respond to this in the generic TSocket class.
  463. //
  464. TSocket::DoCloseNotification(const SOCKET& /*s*/, int /*nError*/)
  465. {
  466.   return 0;
  467. }
  468.  
  469. //
  470. // This should be called by someone that knows what the correct value is.
  471. //
  472. void TSocket::SetMaxReadBufferSize(int maxReadBufferSize)
  473. {
  474.   if(maxReadBufferSize > 0)
  475.     MaxReadBufferSize = maxReadBufferSize;
  476. }
  477.  
  478. //
  479. // Allow transmission of broadcast messages.
  480. //
  481. int TSocket::SetBroadcastOption(bool broadcast)
  482. {
  483.   // Must pass an int, not a bool, to setsockopt
  484.   //
  485.   int bcast = broadcast;
  486.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_BROADCAST, (char*)&bcast, sizeof bcast));
  487. }
  488.  
  489. //
  490. // Record debugging info.
  491. //
  492. int TSocket::SetDebugOption(bool debug)
  493. {
  494.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_DEBUG, (char*)&debug, sizeof debug));
  495. }
  496.  
  497. //
  498. // If you set 'linger' to true, then that means to linger for 'lingerTime' seconds.
  499. // Examples:
  500. //   linger=true, lingerTime=0   Hard immediate close. All queued data for sending gets canned immediately.
  501. //   linger=true, lingerTime=2.  Graceful close, waits 2 seconds to try to send any pending data.
  502. //   linger=false, lingerTime=<any>. "Graceful" immediate close, causes data to still be in queue to send when ready.
  503. //
  504. int TSocket::SetLingerOption(bool linger, ushort lingerTime)
  505. {
  506.   LINGER lingerOptions;
  507.  
  508.   lingerOptions.l_onoff = linger;  //Note that bLinger is a bool and LINGER.l_onoff is a u_short.
  509.   lingerOptions.l_linger = lingerTime;
  510.  
  511.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_LINGER, (char*)&lingerOptions, sizeof lingerOptions));
  512. }
  513.  
  514. //
  515. // A false argument means don't route.
  516. //
  517. int TSocket::SetRouteOption(bool route)
  518. {
  519.   route = !route;
  520.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_DONTROUTE, (char*)&route, sizeof route));
  521. }
  522.  
  523. //
  524. // Send keepAlive messages.
  525. //
  526. int TSocket::SetKeepAliveOption(bool keepAlive)
  527. {
  528.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&keepAlive, sizeof keepAlive));
  529. }
  530.  
  531. //
  532. // Receive out of band data in the normal data stream.
  533. //
  534. int TSocket::SetOOBOption(bool sendOOBDataInline)
  535. {
  536.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_OOBINLINE, (char*)&sendOOBDataInline, sizeof sendOOBDataInline));
  537. }
  538.  
  539. //
  540. // Set the buffer size for receiving messages.
  541. //
  542. int TSocket::SetReceiveBufferOption(int receiveBufferSize)
  543. {
  544.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_RCVBUF, (char*)&receiveBufferSize, sizeof receiveBufferSize));
  545. }
  546.  
  547. //
  548. // Set the buffer size for sending messages.
  549. //
  550. int TSocket::SetSendBufferOption(int sendBufferSize)
  551. {
  552.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufferSize, sizeof sendBufferSize));
  553. }
  554.  
  555. //
  556. // Allow socket to bind to an already bound address
  557. //
  558. int TSocket::SetReuseAddressOption(bool allowReuseAddress)
  559. {
  560.   return SocketsCallCheck(TWinSockDll::setsockopt(Handle, SOL_SOCKET, SO_REUSEADDR, (char*)&allowReuseAddress, sizeof(char*)));
  561. }
  562.  
  563. //
  564. // Retrieve the current broadcast option.
  565. //
  566. int TSocket::GetBroadcastOption(bool& broadcast)
  567. {
  568.   int size = sizeof broadcast;
  569.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, &size));
  570. }
  571.  
  572. //
  573. // Retrieve the current debugging option.
  574. //
  575. int TSocket::GetDebugOption(bool& debug)
  576. {
  577.   int size = sizeof debug;
  578.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_DEBUG, (char*)&debug, &size));
  579. }
  580.  
  581. //
  582. // Retreive the current linger option.
  583. //
  584. int TSocket::GetLingerOption(bool& linger, ushort& lingerTime)
  585. {
  586.   LINGER lingerOptions;
  587.   int size = sizeof lingerOptions;
  588.  
  589.   if (SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_LINGER, (char*)&lingerOptions, &size)) == WINSOCK_NOERROR) {
  590.     linger = lingerOptions.l_onoff;
  591.     lingerTime = lingerOptions.l_linger;
  592.     return WINSOCK_NOERROR;
  593.   }
  594.   return WINSOCK_ERROR;
  595. }
  596.  
  597. //
  598. // Retrieve the routing option.
  599. //
  600. int TSocket::GetRouteOption(bool& route)
  601. {
  602.   int size = sizeof route;
  603.   if (SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_DONTROUTE, (char*)&route, &size)) == WINSOCK_NOERROR) {
  604.     // route value of true means "don't route."  So we change it to mean what
  605.     // you'd think.
  606.     //
  607.     route = !route;
  608.     return WINSOCK_NOERROR;
  609.   }
  610.   return WINSOCK_ERROR;
  611. }
  612.  
  613. //
  614. // Retrieve the keepAlive option.
  615. //
  616. int TSocket::GetKeepAliveOption(bool& keepAlive)
  617. {
  618.   int size = sizeof keepAlive;
  619.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&keepAlive, &size));
  620. }
  621.  
  622. //
  623. // Retrieve the out-of-band option.
  624. //
  625. int TSocket::GetOOBOption(bool& sendOOBDataInline)
  626. {
  627.   int size = sizeof sendOOBDataInline;
  628.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_OOBINLINE, (char*)&sendOOBDataInline, &size));
  629. }
  630.  
  631. //
  632. // Retrieve the current receiving buffer size.
  633. //
  634. int TSocket::GetReceiveBufferOption(int& receiveBufferSize)
  635. {
  636.   int size = sizeof receiveBufferSize;
  637.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_RCVBUF, (char*)&receiveBufferSize, &size));
  638. }
  639.  
  640. //
  641. // Retrieve the current sending buffer size.
  642. //
  643. int TSocket::GetSendBufferOption(int& sendBufferSize)
  644. {
  645.   int size = sizeof sendBufferSize;
  646.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_SNDBUF, (char*)&sendBufferSize, &size));
  647. }
  648.  
  649. //
  650. // Retrieve the reusable address option.
  651. //
  652. int TSocket::GetReuseAddressOption(bool& allowReuseAddress)
  653. {
  654.   int size = sizeof allowReuseAddress;
  655.   return SocketsCallCheck(TWinSockDll::getsockopt(Handle, SOL_SOCKET, SO_REUSEADDR, (char*)&allowReuseAddress, &size));
  656. }
  657.  
  658. //----------------------------------------------------------------------------
  659.  
  660. //
  661. //
  662. //
  663. DEFINE_RESPONSE_TABLE1(TSocketWindow, TWindow)
  664.   EV_MESSAGE(MSG_SOCKET_NOTIFY, DoNotification),
  665. END_RESPONSE_TABLE;
  666.  
  667. //
  668. // Default this to be our standard MSG_SOCKET_NOTIFY
  669. //
  670. uint TSocketWindow::MsgSocketNotification = MSG_SOCKET_NOTIFY;
  671.  
  672. TSocketWindow::TSocketWindow(TSocket* socketParent)
  673. :
  674.   TWindow(0, "TSocketWindow"),
  675.   SelectOptions(0),
  676.   NotificationSet(NotifyAll),
  677.   WindowNotification(0),
  678.   SocketParent(socketParent)
  679. {
  680.   Attr.Style = 0;  // Turn off WS_CHILD (the default) style.
  681. }
  682.  
  683. //
  684. // From the user's standpoint, the only thing that is required to make two SocketWindows
  685. //  act as equal is to make their parents and selection options the same.  The actual
  686. //  window handle identities are unimportant.  Thus, we keep our original Window handle,
  687. //  even if the newSocketWindow had an empty window handle.
  688. //
  689. // However, it may be impossible to assign the parent correctly if this operator is being called
  690. //  in the parent's operator=().  The new parent SHOULD be the original parent, yet the
  691. //  newSocketWindow has a new parent.  We cannot know in this function the conditions
  692. //  under which this assignment is called, so we blindly copy the new parent.
  693. //  The parent will have to override this assignment if the old parent is to
  694. //  remain as it was.
  695. //
  696. // This function does the best it can to make this window act just like newSocketWindow:
  697. //
  698. TSocketWindow& TSocketWindow::operator =(TSocketWindow& src)
  699. {
  700.   SelectOptions      = src.SelectOptions;
  701.   SocketParent       = src.SocketParent;
  702.   WindowNotification = src.WindowNotification;
  703.   NotificationSet    = src.NotificationSet;
  704.  
  705.   if (SocketParent->Handle) {
  706.     // Note that if SelectOptions were empty (0), then we are saying to turn
  707.     //  off notifications and make the socket blocking.
  708.     //
  709.     TWinSockDll::WSAAsyncSelect(SocketParent->Handle, *this, MSG_SOCKET_NOTIFY, SelectOptions);
  710.   }
  711.   return *this;
  712. }
  713.  
  714. //
  715. // This function says to only listen to FD_ACCEPT messages.  It is important to note that a
  716. //  socket set up to be a listening socket will never be a connected socket, and a connected
  717. //  socket will never receive FD_ACCEPT messages.  Thus all stream sockets are implicitly either
  718. //  connected sockets or listening sockets.
  719. //
  720. // Since the accepted socket will want to have a different notification window than the
  721. //  listening socket, and the sockets specification says that an accepted socket
  722. //  inherits the notification properties of the listening socket, it is imperative
  723. //  that the listening socket not be set to receive FD_READ, etc notifications.  This
  724. //  is because it is possible that between the accept() call for the new socket and
  725. //  the WSAAsyncSelect() call for the new socket, data may be received for the new socket.
  726. //  Thus the listening socket may get sent the message and it would never get routed to
  727. //  the new socket.
  728. //
  729. // Calling this function is saying that this SocketWindow is for listening for connections.
  730. //
  731. // The return value is WINSOCK_ERROR or WINSOCK_NOERROR.  You can then examine GetLastError().
  732. //
  733. int TSocketWindow::StartAcceptNotification()
  734. {
  735.   SelectOptions = FD_ACCEPT;
  736.   return StartCustomNotification(SelectOptions);
  737. }
  738.  
  739. //
  740. // This function turns on all Winsock notifications except FD_ACCEPT.
  741. //
  742. // Calling this function is saying that this SocketWindow is for connections rather
  743. // than for listening.  Since a Winsock socket cannot be a listening socket and
  744. // a connected socket at the same time, we have serarate the notification functions
  745. // from each other: StartAcceptNotification() and StartRegularNotification().
  746. //
  747. // The return value is WINSOCK_ERROR or WINSOCK_NOERROR.  You can then examine
  748. // GetLastError().
  749. //
  750. int TSocketWindow::StartRegularNotification()
  751. {
  752.   SelectOptions = FD_ALL & ~FD_ACCEPT;
  753.   return StartCustomNotification(SelectOptions);
  754. }
  755.  
  756. //
  757. // The return value is WINSOCK_ERROR or WINSOCK_NOERROR.  You can then examine
  758. // GetLastError().
  759. //
  760. int TSocketWindow::StartCustomNotification(int selectOptions)
  761. {
  762.   SelectOptions = selectOptions;
  763.  
  764.   int error = TWinSockDll::WSAAsyncSelect(*SocketParent, *this, MSG_SOCKET_NOTIFY, SelectOptions);
  765.   if (error) {
  766.     LastError = TWinSockDll::WSAGetLastError();
  767.     return WINSOCK_ERROR;
  768.   }
  769.   return WINSOCK_NOERROR;
  770. }
  771.  
  772. //
  773. // CancelNotification() turns off the notification to this window. This also changes the
  774. //  socket to be blocking.
  775. // The return value is WINSOCK_ERROR or WINSOCK_NOERROR.  You can then examine GetLastError().
  776. //
  777. int TSocketWindow::CancelNotification()
  778. {
  779.   SelectOptions = 0;
  780.   return StartCustomNotification(SelectOptions);
  781. }
  782.  
  783. //
  784. // DoNotification() is the SocketWindow's protected internal notification system.
  785. //
  786. TResult TSocketWindow::DoNotification(TParam1 param1, TParam2 param2)
  787. {
  788.   SOCKET& socket = param1;
  789.   int     error   = (int)WSAGETSELECTERROR(param2);
  790.  
  791.   if (socket != SocketParent->Handle)
  792.     return 0;
  793.  
  794.   switch (WSAGETSELECTEVENT(param2)) {
  795.     case FD_READ:
  796.       if (WindowNotification && (NotificationSet & NotifyRead)) {
  797.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  798.       }
  799.       SocketParent->DoReadNotification(socket, error);
  800.       break;
  801.     case FD_WRITE:
  802.       if (WindowNotification && (NotificationSet & NotifyWrite)) {
  803.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  804.       }
  805.       SocketParent->DoWriteNotification(socket, error);
  806.       break;
  807.     case FD_OOB:
  808.       if (WindowNotification && (NotificationSet & NotifyOOB)) {
  809.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  810.       }
  811.       SocketParent->DoOOBNotification(socket, error);
  812.       break;
  813.     case FD_ACCEPT:
  814.       if (WindowNotification && (NotificationSet & NotifyAccept)) {
  815.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  816.       }
  817.       SocketParent->DoAcceptNotification(socket, error);
  818.       break;
  819.     case FD_CONNECT:
  820.       if (WindowNotification && (NotificationSet & NotifyConnect)) {
  821.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  822.       }
  823.       SocketParent->DoConnectNotification(socket, error);
  824.       break;
  825.     case FD_CLOSE:
  826.       if (WindowNotification && (NotificationSet & NotifyClose)) {
  827.         return WindowNotification->SendMessage(MsgSocketNotification, param1, param2);
  828.       }
  829.       SocketParent->DoCloseNotification(socket, error);
  830.   }
  831.   return 1;
  832. }
  833.